/**
 ******************************************************************************
 * @file    stm32h5xx_hal_eth_ex.c
 * @author  MCD Application Team
 * @brief   ETH HAL Extended module driver.
 *
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "stm32h5xx_hal.h"

/** @addtogroup STM32H5xx_HAL_Driver
 * @{
 */

#ifdef HAL_ETH_MODULE_ENABLED

    #if defined( ETH )

/** @defgroup ETHEx ETHEx
 * @brief ETH HAL Extended module driver
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/** @defgroup ETHEx_Private_Constants ETHEx Private Constants
 * @{
 */
        #define ETH_MACL4CR_MASK                   \
    ( ETH_MACL3L4CR_L4PEN | ETH_MACL3L4CR_L4SPM |  \
      ETH_MACL3L4CR_L4SPIM | ETH_MACL3L4CR_L4DPM | \
      ETH_MACL3L4CR_L4DPIM )

        #define ETH_MACL3CR_MASK                    \
    ( ETH_MACL3L4CR_L3PEN | ETH_MACL3L4CR_L3SAM |   \
      ETH_MACL3L4CR_L3SAIM | ETH_MACL3L4CR_L3DAM |  \
      ETH_MACL3L4CR_L3DAIM | ETH_MACL3L4CR_L3HSBM | \
      ETH_MACL3L4CR_L3HDBM )

        #define ETH_MACRXVLAN_MASK            \
    ( ETH_MACVTR_EIVLRXS | ETH_MACVTR_EIVLS | \
      ETH_MACVTR_ERIVLT | ETH_MACVTR_EDVLP |  \
      ETH_MACVTR_VTHM | ETH_MACVTR_EVLRXS |   \
      ETH_MACVTR_EVLS | ETH_MACVTR_DOVLTC |   \
      ETH_MACVTR_ERSVLM | ETH_MACVTR_ESVL |   \
      ETH_MACVTR_VTIM | ETH_MACVTR_ETV )

        #define ETH_MACTXVLAN_MASK        \
    ( ETH_MACVIR_VLTI | ETH_MACVIR_CSVL | \
      ETH_MACVIR_VLP | ETH_MACVIR_VLC )

        #define ETH_MAC_L4_SRSP_MASK    0x0000FFFFU
        #define ETH_MAC_L4_DSTP_MASK    0xFFFF0000U

/**
 * @}
 */

/* Private macros ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions ---------------------------------------------------------*/

/** @defgroup ETHEx_Exported_Functions ETH Extended Exported Functions
 * @{
 */

/** @defgroup ETHEx_Exported_Functions_Group1 Extended features functions
 * @brief    Extended features functions
 *
 * @verbatim
 * ===============================================================================
 ##### Extended features functions #####
 #####===============================================================================
 #####[..] This section provides functions allowing to:
 #####(+) Configure ARP offload module
 #####(+) Configure L3 and L4 filters
 #####(+) Configure Extended VLAN features
 #####(+) Configure Energy Efficient Ethernet module
 #####
 #####@endverbatim
 * @{
 */

/**
 * @brief  Enables ARP Offload.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None
 */

        void HAL_ETHEx_EnableARPOffload( ETH_HandleTypeDef * heth )
        {
            SET_BIT( heth->Instance->MACCR, ETH_MACCR_ARP );
        }

/**
 * @brief  Disables ARP Offload.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None
 */
        void HAL_ETHEx_DisableARPOffload( ETH_HandleTypeDef * heth )
        {
            CLEAR_BIT( heth->Instance->MACCR, ETH_MACCR_ARP );
        }

/**
 * @brief  Set the ARP Match IP address
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  IpAddress: IP Address to be matched for incoming ARP requests
 * @retval None
 */
        void HAL_ETHEx_SetARPAddressMatch( ETH_HandleTypeDef * heth,
                                           uint32_t IpAddress )
        {
            WRITE_REG( heth->Instance->MACARPAR, IpAddress );
        }

/**
 * @brief  Configures the L4 Filter, this function allow to:
 *         set the layer 4 protocol to be matched (TCP or UDP)
 *         enable/disable L4 source/destination port perfect/inverse match.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  Filter: L4 filter to configured, this parameter must be one of the following
 *           ETH_L4_FILTER_0
 *           ETH_L4_FILTER_1
 * @param  pL4FilterConfig: pointer to a ETH_L4FilterConfigTypeDef structure
 *         that contains L4 filter configuration.
 * @retval HAL status
 */
        HAL_StatusTypeDef HAL_ETHEx_SetL4FilterConfig( ETH_HandleTypeDef * heth,
                                                       uint32_t Filter,
                                                       const ETH_L4FilterConfigTypeDef * pL4FilterConfig )
        {
            if( pL4FilterConfig == NULL )
            {
                return HAL_ERROR;
            }

            if( Filter == ETH_L4_FILTER_0 )
            {
                /* Write configuration to MACL3L4C0R register */
                MODIFY_REG( heth->Instance->MACL3L4C0R, ETH_MACL4CR_MASK, ( pL4FilterConfig->Protocol |
                                                                            pL4FilterConfig->SrcPortFilterMatch |
                                                                            pL4FilterConfig->DestPortFilterMatch ) );

                /* Write configuration to MACL4A0R register */
                WRITE_REG( heth->Instance->MACL4A0R, ( pL4FilterConfig->SourcePort | ( pL4FilterConfig->DestinationPort << 16 ) ) );
            }
            else /* Filter == ETH_L4_FILTER_1 */
            {
                /* Write configuration to MACL3L4C1R register */
                MODIFY_REG( heth->Instance->MACL3L4C1R, ETH_MACL4CR_MASK, ( pL4FilterConfig->Protocol |
                                                                            pL4FilterConfig->SrcPortFilterMatch |
                                                                            pL4FilterConfig->DestPortFilterMatch ) );

                /* Write configuration to MACL4A1R register */
                WRITE_REG( heth->Instance->MACL4A1R, ( pL4FilterConfig->SourcePort | ( pL4FilterConfig->DestinationPort << 16 ) ) );
            }

            /* Enable L4 filter */
            SET_BIT( heth->Instance->MACPFR, ETH_MACPFR_IPFE );

            return HAL_OK;
        }

/**
 * @brief  Configures the L4 Filter, this function allow to:
 *         set the layer 4 protocol to be matched (TCP or UDP)
 *         enable/disable L4 source/destination port perfect/inverse match.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  Filter: L4 filter to configured, this parameter must be one of the following
 *           ETH_L4_FILTER_0
 *           ETH_L4_FILTER_1
 * @param  pL4FilterConfig: pointer to a ETH_L4FilterConfigTypeDef structure
 *         that contains L4 filter configuration.
 * @retval HAL status
 */
        HAL_StatusTypeDef HAL_ETHEx_GetL4FilterConfig( const ETH_HandleTypeDef * heth,
                                                       uint32_t Filter,
                                                       ETH_L4FilterConfigTypeDef * pL4FilterConfig )
        {
            if( pL4FilterConfig == NULL )
            {
                return HAL_ERROR;
            }

            if( Filter == ETH_L4_FILTER_0 )
            {
                /* Get configuration from MACL3L4C0R register */
                pL4FilterConfig->Protocol = READ_BIT( heth->Instance->MACL3L4C0R, ETH_MACL3L4CR_L4PEN );
                pL4FilterConfig->DestPortFilterMatch = READ_BIT( heth->Instance->MACL3L4C0R,
                                                                 ( ETH_MACL3L4CR_L4DPM | ETH_MACL3L4CR_L4DPIM ) );
                pL4FilterConfig->SrcPortFilterMatch = READ_BIT( heth->Instance->MACL3L4C0R,
                                                                ( ETH_MACL3L4CR_L4SPM | ETH_MACL3L4CR_L4SPIM ) );

                /* Get configuration from MACL4A0R register */
                pL4FilterConfig->DestinationPort = ( READ_BIT( heth->Instance->MACL4A0R, ETH_MAC_L4_DSTP_MASK ) >> 16 );
                pL4FilterConfig->SourcePort = READ_BIT( heth->Instance->MACL4A0R, ETH_MAC_L4_SRSP_MASK );
            }
            else /* Filter == ETH_L4_FILTER_1 */
            {
                /* Get configuration from MACL3L4C1R register */
                pL4FilterConfig->Protocol = READ_BIT( heth->Instance->MACL3L4C1R, ETH_MACL3L4CR_L4PEN );
                pL4FilterConfig->DestPortFilterMatch = READ_BIT( heth->Instance->MACL3L4C1R,
                                                                 ( ETH_MACL3L4CR_L4DPM | ETH_MACL3L4CR_L4DPIM ) );
                pL4FilterConfig->SrcPortFilterMatch = READ_BIT( heth->Instance->MACL3L4C1R,
                                                                ( ETH_MACL3L4CR_L4SPM | ETH_MACL3L4CR_L4SPIM ) );

                /* Get configuration from MACL4A1R register */
                pL4FilterConfig->DestinationPort = ( READ_BIT( heth->Instance->MACL4A1R, ETH_MAC_L4_DSTP_MASK ) >> 16 );
                pL4FilterConfig->SourcePort = READ_BIT( heth->Instance->MACL4A1R, ETH_MAC_L4_SRSP_MASK );
            }

            return HAL_OK;
        }

/**
 * @brief  Configures the L3 Filter, this function allow to:
 *         set the layer 3 protocol to be matched (IPv4 or IPv6)
 *         enable/disable L3 source/destination port perfect/inverse match.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  Filter: L3 filter to configured, this parameter must be one of the following
 *           ETH_L3_FILTER_0
 *           ETH_L3_FILTER_1
 * @param  pL3FilterConfig: pointer to a ETH_L3FilterConfigTypeDef structure
 *         that contains L3 filter configuration.
 * @retval HAL status
 */
        HAL_StatusTypeDef HAL_ETHEx_SetL3FilterConfig( ETH_HandleTypeDef * heth,
                                                       uint32_t Filter,
                                                       const ETH_L3FilterConfigTypeDef * pL3FilterConfig )
        {
            if( pL3FilterConfig == NULL )
            {
                return HAL_ERROR;
            }

            if( Filter == ETH_L3_FILTER_0 )
            {
                /* Write configuration to MACL3L4C0R register */
                MODIFY_REG( heth->Instance->MACL3L4C0R, ETH_MACL3CR_MASK, ( pL3FilterConfig->Protocol |
                                                                            pL3FilterConfig->SrcAddrFilterMatch |
                                                                            pL3FilterConfig->DestAddrFilterMatch |
                                                                            ( pL3FilterConfig->SrcAddrHigherBitsMatch << 6 ) |
                                                                            ( pL3FilterConfig->DestAddrHigherBitsMatch << 11 ) ) );
            }
            else /* Filter == ETH_L3_FILTER_1 */
            {
                /* Write configuration to MACL3L4C1R register */
                MODIFY_REG( heth->Instance->MACL3L4C1R, ETH_MACL3CR_MASK, ( pL3FilterConfig->Protocol |
                                                                            pL3FilterConfig->SrcAddrFilterMatch |
                                                                            pL3FilterConfig->DestAddrFilterMatch |
                                                                            ( pL3FilterConfig->SrcAddrHigherBitsMatch << 6 ) |
                                                                            ( pL3FilterConfig->DestAddrHigherBitsMatch << 11 ) ) );
            }

            if( Filter == ETH_L3_FILTER_0 )
            {
                /* Check if IPv6 protocol is selected */
                if( pL3FilterConfig->Protocol != ETH_L3_IPV4_MATCH )
                {
                    /* Set the IPv6 address match */
                    /* Set Bits[31:0] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A0R0R, pL3FilterConfig->Ip6Addr[ 0 ] );
                    /* Set Bits[63:32] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A1R0R, pL3FilterConfig->Ip6Addr[ 1 ] );
                    /* update Bits[95:64] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A2R0R, pL3FilterConfig->Ip6Addr[ 2 ] );
                    /* update Bits[127:96] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A3R0R, pL3FilterConfig->Ip6Addr[ 3 ] );
                }
                else /* IPv4 protocol is selected */
                {
                    /* Set the IPv4 source address match */
                    WRITE_REG( heth->Instance->MACL3A0R0R, pL3FilterConfig->Ip4SrcAddr );
                    /* Set the IPv4 destination address match */
                    WRITE_REG( heth->Instance->MACL3A1R0R, pL3FilterConfig->Ip4DestAddr );
                }
            }
            else /* Filter == ETH_L3_FILTER_1 */
            {
                /* Check if IPv6 protocol is selected */
                if( pL3FilterConfig->Protocol != ETH_L3_IPV4_MATCH )
                {
                    /* Set the IPv6 address match */
                    /* Set Bits[31:0] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A0R1R, pL3FilterConfig->Ip6Addr[ 0 ] );
                    /* Set Bits[63:32] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A1R1R, pL3FilterConfig->Ip6Addr[ 1 ] );
                    /* update Bits[95:64] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A1R1R, pL3FilterConfig->Ip6Addr[ 2 ] );
                    /* update Bits[127:96] of 128-bit IP addr */
                    WRITE_REG( heth->Instance->MACL3A1R1R, pL3FilterConfig->Ip6Addr[ 3 ] );
                }
                else /* IPv4 protocol is selected */
                {
                    /* Set the IPv4 source address match */
                    WRITE_REG( heth->Instance->MACL3A0R1R, pL3FilterConfig->Ip4SrcAddr );
                    /* Set the IPv4 destination address match */
                    WRITE_REG( heth->Instance->MACL3A0R1R, pL3FilterConfig->Ip4DestAddr );
                }
            }

            /* Enable L3 filter */
            SET_BIT( heth->Instance->MACPFR, ETH_MACPFR_IPFE );

            return HAL_OK;
        }

/**
 * @brief  Configures the L3 Filter, this function allow to:
 *         set the layer 3 protocol to be matched (IPv4 or IPv6)
 *         enable/disable L3 source/destination port perfect/inverse match.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  Filter: L3 filter to configured, this parameter must be one of the following
 *           ETH_L3_FILTER_0
 *           ETH_L3_FILTER_1
 * @param  pL3FilterConfig: pointer to a ETH_L3FilterConfigTypeDef structure
 *         that will contain the L3 filter configuration.
 * @retval HAL status
 */
        HAL_StatusTypeDef HAL_ETHEx_GetL3FilterConfig( const ETH_HandleTypeDef * heth,
                                                       uint32_t Filter,
                                                       ETH_L3FilterConfigTypeDef * pL3FilterConfig )
        {
            if( pL3FilterConfig == NULL )
            {
                return HAL_ERROR;
            }

            pL3FilterConfig->Protocol = READ_BIT( *( ( __IO uint32_t * ) ( &( heth->Instance->MACL3L4C0R ) + Filter ) ),
                                                  ETH_MACL3L4CR_L3PEN );
            pL3FilterConfig->SrcAddrFilterMatch = READ_BIT( *( ( __IO uint32_t * ) ( &( heth->Instance->MACL3L4C0R ) + Filter ) ),
                                                            ( ETH_MACL3L4CR_L3SAM | ETH_MACL3L4CR_L3SAIM ) );
            pL3FilterConfig->DestAddrFilterMatch = READ_BIT( *( ( __IO uint32_t * ) ( &( heth->Instance->MACL3L4C0R ) + Filter ) ),
                                                             ( ETH_MACL3L4CR_L3DAM | ETH_MACL3L4CR_L3DAIM ) );
            pL3FilterConfig->SrcAddrHigherBitsMatch = ( READ_BIT( *( ( __IO uint32_t * ) ( &( heth->Instance->MACL3L4C0R ) + Filter ) ),
                                                                  ETH_MACL3L4CR_L3HSBM ) >> 6 );
            pL3FilterConfig->DestAddrHigherBitsMatch = ( READ_BIT( *( ( __IO uint32_t * ) ( &( heth->Instance->MACL3L4C0R ) + Filter ) ),
                                                                   ETH_MACL3L4CR_L3HDBM ) >> 11 );

            if( Filter == ETH_L3_FILTER_0 )
            {
                if( pL3FilterConfig->Protocol != ETH_L3_IPV4_MATCH )
                {
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 0 ], heth->Instance->MACL3A0R0R );
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 1 ], heth->Instance->MACL3A1R0R );
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 2 ], heth->Instance->MACL3A2R0R );
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 3 ], heth->Instance->MACL3A3R0R );
                }
                else
                {
                    WRITE_REG( pL3FilterConfig->Ip4SrcAddr, heth->Instance->MACL3A0R0R );
                    WRITE_REG( pL3FilterConfig->Ip4DestAddr, heth->Instance->MACL3A1R0R );
                }
            }
            else /* ETH_L3_FILTER_1 */
            {
                if( pL3FilterConfig->Protocol != ETH_L3_IPV4_MATCH )
                {
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 0 ], heth->Instance->MACL3A0R1R );
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 1 ], heth->Instance->MACL3A1R1R );
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 2 ], heth->Instance->MACL3A2R1R );
                    WRITE_REG( pL3FilterConfig->Ip6Addr[ 3 ], heth->Instance->MACL3A3R1R );
                }
                else
                {
                    WRITE_REG( pL3FilterConfig->Ip4SrcAddr, heth->Instance->MACL3A0R1R );
                    WRITE_REG( pL3FilterConfig->Ip4DestAddr, heth->Instance->MACL3A1R1R );
                }
            }

            return HAL_OK;
        }

/**
 * @brief  Enables L3 and L4 filtering process.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None.
 */
        void HAL_ETHEx_EnableL3L4Filtering( ETH_HandleTypeDef * heth )
        {
            /* Enable L3/L4 filter */
            SET_BIT( heth->Instance->MACPFR, ETH_MACPFR_IPFE );
        }

/**
 * @brief  Disables L3 and L4 filtering process.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None.
 */
        void HAL_ETHEx_DisableL3L4Filtering( ETH_HandleTypeDef * heth )
        {
            /* Disable L3/L4 filter */
            CLEAR_BIT( heth->Instance->MACPFR, ETH_MACPFR_IPFE );
        }

/**
 * @brief  Get the VLAN Configuration for Receive Packets.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  pVlanConfig: pointer to a ETH_RxVLANConfigTypeDef structure
 *         that will contain the VLAN filter configuration.
 * @retval HAL status
 */
        HAL_StatusTypeDef HAL_ETHEx_GetRxVLANConfig( const ETH_HandleTypeDef * heth,
                                                     ETH_RxVLANConfigTypeDef * pVlanConfig )
        {
            if( pVlanConfig == NULL )
            {
                return HAL_ERROR;
            }

            pVlanConfig->InnerVLANTagInStatus = ( ( READ_BIT( heth->Instance->MACVTR,
                                                              ETH_MACVTR_EIVLRXS ) >> 31 ) == 0U ) ? DISABLE : ENABLE;
            pVlanConfig->StripInnerVLANTag = READ_BIT( heth->Instance->MACVTR, ETH_MACVTR_EIVLS );
            pVlanConfig->InnerVLANTag = ( ( READ_BIT( heth->Instance->MACVTR,
                                                      ETH_MACVTR_ERIVLT ) >> 27 ) == 0U ) ? DISABLE : ENABLE;
            pVlanConfig->DoubleVLANProcessing = ( ( READ_BIT( heth->Instance->MACVTR,
                                                              ETH_MACVTR_EDVLP ) >> 26 ) == 0U ) ? DISABLE : ENABLE;
            pVlanConfig->VLANTagHashTableMatch = ( ( READ_BIT( heth->Instance->MACVTR,
                                                               ETH_MACVTR_VTHM ) >> 25 ) == 0U ) ? DISABLE : ENABLE;
            pVlanConfig->VLANTagInStatus = ( ( READ_BIT( heth->Instance->MACVTR,
                                                         ETH_MACVTR_EVLRXS ) >> 24 ) == 0U ) ? DISABLE : ENABLE;
            pVlanConfig->StripVLANTag = READ_BIT( heth->Instance->MACVTR, ETH_MACVTR_EVLS );
            pVlanConfig->VLANTypeCheck = READ_BIT( heth->Instance->MACVTR,
                                                   ( ETH_MACVTR_DOVLTC | ETH_MACVTR_ERSVLM | ETH_MACVTR_ESVL ) );
            pVlanConfig->VLANTagInverceMatch = ( ( READ_BIT( heth->Instance->MACVTR, ETH_MACVTR_VTIM ) >> 17 ) == 0U )
                                               ? DISABLE : ENABLE;

            return HAL_OK;
        }

/**
 * @brief  Set the VLAN Configuration for Receive Packets.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  pVlanConfig: pointer to a ETH_RxVLANConfigTypeDef structure
 *         that contains VLAN filter configuration.
 * @retval HAL status
 */
        HAL_StatusTypeDef HAL_ETHEx_SetRxVLANConfig( ETH_HandleTypeDef * heth,
                                                     ETH_RxVLANConfigTypeDef * pVlanConfig )
        {
            if( pVlanConfig == NULL )
            {
                return HAL_ERROR;
            }

            /* Write config to MACVTR */
            MODIFY_REG( heth->Instance->MACVTR, ETH_MACRXVLAN_MASK, ( ( ( uint32_t ) pVlanConfig->InnerVLANTagInStatus << 31 ) |
                                                                      pVlanConfig->StripInnerVLANTag |
                                                                      ( ( uint32_t ) pVlanConfig->InnerVLANTag << 27 ) |
                                                                      ( ( uint32_t ) pVlanConfig->DoubleVLANProcessing << 26 ) |
                                                                      ( ( uint32_t ) pVlanConfig->VLANTagHashTableMatch << 25 ) |
                                                                      ( ( uint32_t ) pVlanConfig->VLANTagInStatus << 24 ) |
                                                                      pVlanConfig->StripVLANTag |
                                                                      pVlanConfig->VLANTypeCheck |
                                                                      ( ( uint32_t ) pVlanConfig->VLANTagInverceMatch << 17 ) ) );

            return HAL_OK;
        }

/**
 * @brief  Set the VLAN Hash Table
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  VLANHashTable: VLAN hash table 16 bit value
 * @retval None
 */
        void HAL_ETHEx_SetVLANHashTable( ETH_HandleTypeDef * heth,
                                         uint32_t VLANHashTable )
        {
            MODIFY_REG( heth->Instance->MACVHTR, ETH_MACVHTR_VLHT, VLANHashTable );
        }

/**
 * @brief  Get the VLAN Configuration for Transmit Packets.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  VLANTag: Selects the vlan tag, this parameter must be one of the following
 *                 ETH_OUTER_TX_VLANTAG
 *                 ETH_INNER_TX_VLANTAG
 * @param  pVlanConfig: pointer to a ETH_TxVLANConfigTypeDef structure
 *         that will contain the Tx VLAN filter configuration.
 * @retval HAL Status.
 */
        HAL_StatusTypeDef HAL_ETHEx_GetTxVLANConfig( const ETH_HandleTypeDef * heth,
                                                     uint32_t VLANTag,
                                                     ETH_TxVLANConfigTypeDef * pVlanConfig )
        {
            if( pVlanConfig == NULL )
            {
                return HAL_ERROR;
            }

            if( VLANTag == ETH_INNER_TX_VLANTAG )
            {
                pVlanConfig->SourceTxDesc = ( ( READ_BIT( heth->Instance->MACIVIR, ETH_MACVIR_VLTI ) >> 20 ) == 0U ) ? DISABLE : ENABLE;
                pVlanConfig->SVLANType = ( ( READ_BIT( heth->Instance->MACIVIR, ETH_MACVIR_CSVL ) >> 19 ) == 0U ) ? DISABLE : ENABLE;
                pVlanConfig->VLANTagControl = READ_BIT( heth->Instance->MACIVIR, ( ETH_MACVIR_VLP | ETH_MACVIR_VLC ) );
            }
            else
            {
                pVlanConfig->SourceTxDesc = ( ( READ_BIT( heth->Instance->MACVIR, ETH_MACVIR_VLTI ) >> 20 ) == 0U ) ? DISABLE : ENABLE;
                pVlanConfig->SVLANType = ( ( READ_BIT( heth->Instance->MACVIR, ETH_MACVIR_CSVL ) >> 19 ) == 0U ) ? DISABLE : ENABLE;
                pVlanConfig->VLANTagControl = READ_BIT( heth->Instance->MACVIR, ( ETH_MACVIR_VLP | ETH_MACVIR_VLC ) );
            }

            return HAL_OK;
        }

/**
 * @brief  Set the VLAN Configuration for Transmit Packets.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  VLANTag: Selects the vlan tag, this parameter must be one of the following
 *                 ETH_OUTER_TX_VLANTAG
 *                 ETH_INNER_TX_VLANTAG
 * @param  pVlanConfig: pointer to a ETH_TxVLANConfigTypeDef structure
 *         that contains Tx VLAN filter configuration.
 * @retval HAL Status
 */
        HAL_StatusTypeDef HAL_ETHEx_SetTxVLANConfig( ETH_HandleTypeDef * heth,
                                                     uint32_t VLANTag,
                                                     const ETH_TxVLANConfigTypeDef * pVlanConfig )
        {
            if( VLANTag == ETH_INNER_TX_VLANTAG )
            {
                MODIFY_REG( heth->Instance->MACIVIR, ETH_MACTXVLAN_MASK, ( ( ( uint32_t ) pVlanConfig->SourceTxDesc << 20 ) |
                                                                           ( ( uint32_t ) pVlanConfig->SVLANType << 19 ) |
                                                                           pVlanConfig->VLANTagControl ) );
                /* Enable Double VLAN processing */
                SET_BIT( heth->Instance->MACVTR, ETH_MACVTR_EDVLP );
            }
            else
            {
                MODIFY_REG( heth->Instance->MACVIR, ETH_MACTXVLAN_MASK, ( ( ( uint32_t ) pVlanConfig->SourceTxDesc << 20 ) |
                                                                          ( ( uint32_t ) pVlanConfig->SVLANType << 19 ) |
                                                                          pVlanConfig->VLANTagControl ) );
            }

            return HAL_OK;
        }

/**
 * @brief  Set the VLAN Tag Identifier for Transmit Packets.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  VLANTag: Selects the vlan tag, this parameter must be one of the following
 *                 ETH_OUTER_TX_VLANTAG
 *                 ETH_INNER_TX_VLANTAG
 * @param  VLANIdentifier: VLAN Identifier 16 bit value
 * @retval None
 */
        void HAL_ETHEx_SetTxVLANIdentifier( ETH_HandleTypeDef * heth,
                                            uint32_t VLANTag,
                                            uint32_t VLANIdentifier )
        {
            if( VLANTag == ETH_INNER_TX_VLANTAG )
            {
                MODIFY_REG( heth->Instance->MACIVIR, ETH_MACVIR_VLT, VLANIdentifier );
            }
            else
            {
                MODIFY_REG( heth->Instance->MACVIR, ETH_MACVIR_VLT, VLANIdentifier );
            }
        }

/**
 * @brief  Enables the VLAN Tag Filtering process.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None.
 */
        void HAL_ETHEx_EnableVLANProcessing( ETH_HandleTypeDef * heth )
        {
            /* Enable VLAN processing */
            SET_BIT( heth->Instance->MACPFR, ETH_MACPFR_VTFE );
        }

/**
 * @brief  Disables the VLAN Tag Filtering process.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None.
 */
        void HAL_ETHEx_DisableVLANProcessing( ETH_HandleTypeDef * heth )
        {
            /* Disable VLAN processing */
            CLEAR_BIT( heth->Instance->MACPFR, ETH_MACPFR_VTFE );
        }

/**
 * @brief  Enters the Low Power Idle (LPI) mode
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @param  TxAutomate: Enable/Disable automate enter/exit LPI mode.
 * @param  TxClockStop: Enable/Disable Tx clock stop in LPI mode.
 * @retval None
 */
        void HAL_ETHEx_EnterLPIMode( ETH_HandleTypeDef * heth,
                                     FunctionalState TxAutomate,
                                     FunctionalState TxClockStop )
        {
            /* Enable LPI Interrupts */
            __HAL_ETH_MAC_ENABLE_IT( heth, ETH_MACIER_LPIIE );

            /* Write to LPI Control register: Enter low power mode */
            MODIFY_REG( heth->Instance->MACLCSR, ( ETH_MACLCSR_LPIEN | ETH_MACLCSR_LPITXA | ETH_MACLCSR_LPITCSE ),
                        ( ( ( uint32_t ) TxAutomate << 19 ) |
                          ( ( uint32_t ) TxClockStop << 21 ) |
                          ETH_MACLCSR_LPIEN ) );
        }

/**
 * @brief  Exits the Low Power Idle (LPI) mode.
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval None
 */
        void HAL_ETHEx_ExitLPIMode( ETH_HandleTypeDef * heth )
        {
            /* Clear the LPI Config and exit low power mode */
            CLEAR_BIT( heth->Instance->MACLCSR, ( ETH_MACLCSR_LPIEN | ETH_MACLCSR_LPITXA | ETH_MACLCSR_LPITCSE ) );

            /* Enable LPI Interrupts */
            __HAL_ETH_MAC_DISABLE_IT( heth, ETH_MACIER_LPIIE );
        }

/**
 * @brief  Returns the ETH MAC LPI event
 * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
 *         the configuration information for ETHERNET module
 * @retval ETH MAC WakeUp event
 */
        uint32_t HAL_ETHEx_GetMACLPIEvent( const ETH_HandleTypeDef * heth )
        {
            return heth->MACLPIEvent;
        }

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */

    #endif /* ETH */

#endif /* HAL_ETH_MODULE_ENABLED */

/**
 * @}
 */
